// *********************************************************************************
// Project Name : zkx2024
// Author       : Jlan
// Email        : 15533610762@163.com
// Create Time  : 2024-04-11
// File Name    : sync_fifo.v
// Module Name  : sync_fifo
// Called By    : jlan
// Abstract     : std_sync_fifo
//
// 
// *********************************************************************************
// Modification History:
// Date         By              Version                 Change Description
// -----------------------------------------------------------------------
// 2024-04-11    Macro           1.0                     Original
//  
// *********************************************************************************



// *********************************************************************************
module sync_fifo(
    input       CLK,
    input       RST_N,
    input       WR_EN,
    input       WR_DATA,
    input       RD_EN,
    input       CLEAR,
    input       FLUSH,
    output      RD_DATA,
    output      FULL,
    output      EMPTY
);

//parameter
parameter       FIFO_WIDTH  =   4;
parameter       FIFO_DEPTH  =   4;

//localparam
localparam      FIFO_ADDR   =   $clog2(FIFO_DEPTH*2);

//IO_define
logic   [0:0]               CLK;
logic   [0:0]               RST_N;
logic   [0:0]               WR_EN;
logic   [FIFO_WIDTH-1:0]    WR_DATA;
logic   [0:0]               RD_EN;
logic   [0:0]               CLEAR;
logic   [0:0]               FLUSH;
logic   [FIFO_WIDTH-1:0]    RD_DATA;
logic   [0:0]               FULL;
logic   [0:0]               EMPTY;

//INTER_SIGNAL_define
logic   [FIFO_ADDR-1:0]     wr_addr;
logic   [FIFO_ADDR-1:0]     rd_addr;
logic   [FIFO_WIDTH-1:0]    fifo_mem    [FIFO_DEPTH-1:0];

//FIFO full empty
assign  FULL = (wr_addr[FIFO_ADDR-1] != rd_addr[FIFO_ADDR-1]) &&
                wr_addr[FIFO_ADDR-2:0] == rd_addr[FIFO_ADDR-2:0];

assign  EMPTY = wr_addr == rd_addr;

always_ff @(posedge CLK or negedge RST_N) begin
    if(!RST_N)
        wr_addr <= '0;
    else if(CLEAR)
        wr_addr <= '0;
    else if(wr_addr==(FIFO_DEPTH-1))
        wr_addr <= '0;
    else if(!FULL&&WR_EN)
        wr_addr <= wr_addr + 1'b1;
end 

always_ff @(posedge CLK or negedge RST_N) begin
    if(!RST_N)
        rd_addr <= '0;
    else if(CLEAR)
        rd_addr <= '0;
    else if(FLUSH&&rd_addr==0)
        rd_addr <= {FIFO_ADDR{1'b1}};
    else if(FLUSH)
        rd_addr <= rd_addr - 1'b1;
    else if(rd_addr==(FIFO_DEPTH-1))
        rd_addr <= '0;
    else if(!EMPTY&&RD_EN)
        rd_addr <= rd_addr + 1'b1;
end 

always_ff @(posedge CLK ) begin
    if(!FULL&&WR_EN)
        fifo_mem[wr_addr[FIFO_ADDR-2:0]] <= WR_DATA;
end 
always_ff @(posedge CLK or negedge RST_N) begin
    if(!RST_N)
        RD_DATA <= '0;
    else if(!EMPTY&&RD_EN)
        RD_DATA <= fifo_mem[rd_addr[FIFO_ADDR-2:0]];
end 

endmodule
